package cron

import (
	"errors"
	"fmt"
	"github.com/alecthomas/log4go"
	"protobuf/model"
	"protobuf/module/setting"
	"protobuf/trade"
	"time"
)

type Error int

const (
	INFO  Error = 0
	WARN  Error = 1
	ERROR Error = 2
)

var Errs map[int]map[Error]error

func init() {
	ticker1 := time.NewTicker(time.Duration(setting.TICKER) * time.Microsecond)
	ticker2 := time.NewTicker(time.Duration(setting.TICKER*3) * time.Microsecond)
	go func() {
		for _ = range ticker1.C {
			Run()
		}
	}()
	go func() {
		for _ = range ticker2.C {
			HandleResult()
		}
	}()
}

func Run() {
	var (
		buyTrade  model.Trade
		sellTrade model.Trade
		tradeLog  model.TradeLog
		rsBuy     model.Result
		rsSell    model.Result
		err       error
		has       bool
	)
	for {
		buyTrade = model.Trade{}
		sellTrade = model.Trade{}
		tradeLog = model.TradeLog{}
		rsBuy = model.Result{}
		rsSell = model.Result{}

		has, err = model.GetOneBuy(&buyTrade)
		if err != nil {
			HandleError(err, WARN)
			break
		}
		if !has {
			break
		}
		has, err = model.GetAllSell(&sellTrade)
		if err != nil {
			HandleError(err, WARN)
			break
		}
		if !has {
			break
		}
		if buyTrade.Price < sellTrade.Price {
			break
		}
		// 容错处理 .
		if buyTrade.TotalNum <= buyTrade.DealNum || buyTrade.LeftNum == 0 {
			buyTrade.Status = trade.TradeRequest_OK
			log4go.Error("错误1：买单错误，记录值：%v", buyTrade)
			err = errors.New(fmt.Sprintf("错误1：买单错误，记录值：%v", buyTrade))
			HandleError(err, ERROR)
			_, err := model.SaveTrade(&buyTrade)
			if err != nil {
				HandleError(err, ERROR)
			}
			break
		}
		if sellTrade.TotalNum <= sellTrade.DealNum || sellTrade.LeftNum == 0 {
			log4go.Error("错误2：卖单错误，记录值：%v", sellTrade)
			err = errors.New(fmt.Sprintf("错误2：卖单错误，记录值：%v", sellTrade))
			HandleError(err, ERROR)
			sellTrade.Status = trade.TradeRequest_OK
			_, err := model.SaveTrade(&sellTrade)
			if err != nil {
				HandleError(err, ERROR)
			}
			break
		}
		// 交易数量为 买卖的小的为准
		if sellTrade.LeftNum > buyTrade.LeftNum {
			// 买 ： 最终结果： 买：deal_num = total_num   left_num = 0
			tradeLog.Num = buyTrade.LeftNum
			buyTrade.LeftNum = 0
			buyTrade.DealNum = buyTrade.TotalNum

			sellTrade.DealNum = sellTrade.DealNum + tradeLog.Num
			sellTrade.LeftNum = sellTrade.LeftNum - tradeLog.Num
		} else {
			// 卖： 最终结果： 卖： deal_num = total_num  left_num = 0
			tradeLog.Num = sellTrade.LeftNum
			sellTrade.LeftNum = 0
			sellTrade.DealNum = sellTrade.TotalNum

			buyTrade.LeftNum = buyTrade.LeftNum - tradeLog.Num
			buyTrade.DealNum = buyTrade.DealNum + tradeLog.Num
		}
		// 计算状态 .
		if buyTrade.TotalNum <= buyTrade.DealNum && buyTrade.LeftNum == 0 {
			buyTrade.Status = trade.TradeRequest_OK
		}
		if sellTrade.TotalNum <= sellTrade.DealNum && sellTrade.LeftNum == 0 {
			sellTrade.Status = trade.TradeRequest_OK
		}

		if sellTrade.Id < buyTrade.Id {
			tradeLog.Type = trade.TradeRequest_SELL // 如果 卖单早于买单， 该笔交易就是卖
			tradeLog.Price = sellTrade.Price
			tradeLog.Uid = sellTrade.Uid
			tradeLog.PeerId = buyTrade.Uid
		} else {
			tradeLog.Type = trade.TradeRequest_BUY // 否则就是买
			tradeLog.Price = buyTrade.Price
			tradeLog.Uid = buyTrade.Uid
			tradeLog.PeerId = sellTrade.Uid
		}

		tradeLog.Amount = tradeLog.Num * tradeLog.Price
		tradeLog.Created = time.Now().Unix()
		tradeLog.Updated = time.Now().Unix()
		buyTrade.Updated = time.Now().Unix()
		sellTrade.Updated = time.Now().Unix()
		//  买卖 ， 日志 计算完毕， 现在计算结果集
		rsBuy.Uid = buyTrade.Uid
		rsBuy.Rmb = 0
		rsBuy.RmbFrozen = tradeLog.Amount * -1 // 买家减少 人民币冻结
		rsBuy.Btc = tradeLog.Num               // 买家增加btc
		rsBuy.BtcFrozen = 0
		rsBuy.Created = time.Now().Unix()
		rsBuy.BuyId = buyTrade.Id
		rsBuy.SellId = sellTrade.Id
		rsBuy.Status = 0

		rsSell.Uid = sellTrade.Uid
		rsSell.Rmb = tradeLog.Num // 卖家增加人民币
		rsSell.RmbFrozen = 0
		rsSell.Btc = 0
		rsSell.BtcFrozen = tradeLog.Amount * -1 // 卖家减少冻结btc
		rsSell.Created = time.Now().Unix()
		rsSell.BuyId = buyTrade.Id
		rsSell.SellId = sellTrade.Id
		rsSell.Status = 0
		log4go.Debug("start==================================================")
		log4go.Debug(buyTrade)
		log4go.Debug(sellTrade)
		log4go.Debug(tradeLog)
		log4go.Debug(rsBuy)
		log4go.Debug(rsSell)
		log4go.Debug("end==================================================")
		// 结果计算完毕 . 插入数据库 .
		db := model.GetEngine()

		session := db.NewSession()
		defer session.Close()
		err := session.Begin()
		if err != nil {
			err = errors.New(fmt.Sprintf("事物开启失败：%v", err))
			HandleError(err, INFO)
			break
		}

		_, err = session.ID(buyTrade.Id).Cols("left_num", "deal_num", "status", "updated").Update(&buyTrade)
		if err != nil {
			err = errors.New(fmt.Sprintf("事物处理失败：%v", err))
			HandleError(err, WARN)
			session.Rollback()
			break
		}
		_, err = session.ID(sellTrade.Id).Cols("left_num", "deal_num", "status", "updated").Update(&sellTrade)
		if err != nil {
			err = errors.New(fmt.Sprintf("事物处理失败：%v", err))
			HandleError(err, WARN)
			session.Rollback()
			break
		}

		_, err = session.Insert(&tradeLog)
		if err != nil {
			err = errors.New(fmt.Sprintf("事物处理失败：%v", err))
			HandleError(err, WARN)
			session.Rollback()
			break
		}
		_, err = session.Insert(&rsBuy)
		if err != nil {
			err = errors.New(fmt.Sprintf("事物处理失败：%v", err))
			HandleError(err, WARN)
			session.Rollback()
			break
		}

		_, err = session.Insert(&rsSell)
		if err != nil {
			err = errors.New(fmt.Sprintf("事物处理失败：%v", err))
			HandleError(err, WARN)
			session.Rollback()
			break
		}
		err = session.Commit()
		Rs <- &rsBuy
		Rs <- &rsSell

		if err != nil {
			err = errors.New(fmt.Sprintf("事物处理失败：%v", err))
			HandleError(err, WARN)
			break
		}
		break
	}
	return
}

func HandleResult() {
	session := model.GetEngine().NewSession()
	defer session.Close()
	rs := make([]*model.Result, 0)
	session.Where("status = ?", 2).Find(&rs)
	if len(rs) != 0 {
		for _, value := range rs {
			Rs <- value
		}
	}
}

func HandleError(err error, level Error) {
	if level == INFO {
		log4go.Info(err)
	}
	if level == WARN {
		log4go.Warn(err)
	}
	if level == ERROR {
		log4go.Error(err)
	}
}
